#include "ComponentLayEggBehavior.h"
#include "ComponentPathfinding.h"
#include "Components/ComponentCreature.h"
#include "Components/ComponentBody.h"
#include "Components/ComponentCreatureSounds.h"
#include "Components/ComponentCreatureModel.h"
#include "Components/ComponentLocomotion.h"

#include "Subsystems/SubsystemTerrain.h"
#include "Subsystems/SubsystemTimeOfDay.h"
#include "Subsystems/SubsystemPickables.h"

#include "GameRandom.hpp"
#include "Engine/MathUtils.hpp"
#include "Log.h"
#include "GameRegistry.hpp"
#include "GameSingleton.h"
#include "GameThreadPool.hpp"
#include "Game/EntityData.hpp"
#include "Blocks/EggBlock.h"
#include "Managers/BlocksManager.h"

#include <iostream>

namespace PocketSurvival
{

    // ************** 【状态机】 **************

    ComponentLayEggBehavior::StateMachine::StateMachine(ComponentLayEggBehavior *layEggBehavior) : m_layEggBehavior(layEggBehavior), EasyMachine(MachineState::Move)
    {
        enter();
    }

    void ComponentLayEggBehavior::StateMachine::enter()
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            break;
        case MachineState::Stuck:
            break;
        case MachineState::Move:
            MACHINE_DELEGATE()
            {
                SubsystemTerrain *terrain = GameSingleton::singletonPtr->getSingleton<SubsystemTerrain>();
                Vector3 position2;
                m_layEggBehavior->componentCreature->componentBody->getPosition(position2);

                float num = 5.0f;
                Vector3 value3 = position2 + Vector3(num * GameSingleton::gameRandom->getFloat(-1.0f, 1.0f), 0, num * GameSingleton::gameRandom->getFloat(-1.0f, 1.0f));
                value3.posY = terrain->getTopHeight(Terrain::ToCell(value3.posX), Terrain::ToCell(value3.posZ)) + 1;
                m_layEggBehavior->componentPathfinding->setDestination(value3, GameSingleton::gameRandom->getFloat(0.4f, 0.6f), 0.05f, 0, false, true ,false, nullptr);
            }
            break;
        case MachineState::Lay:
            // Log::Info("准备下蛋");
            m_layEggBehavior->layTime = 0.0f;
            break;
        }
    }

    void ComponentLayEggBehavior::StateMachine::update(float dt)
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            MACHINE_DELEGATE()
            {
                if (m_layEggBehavior->isActive())
                {
                    changeTo(MachineState::Move);
                }
            }
            break;
        case MachineState::Stuck:
            MACHINE_DELEGATE()
            {
                changeTo(MachineState::Move);
            }
            break;
        case MachineState::Move:
            MACHINE_DELEGATE()
            {
                if (m_layEggBehavior->componentPathfinding->destination == FastVector3::Zero)
                {
                    changeTo(MachineState::Lay);
                }
                else if (m_layEggBehavior->componentPathfinding->isStuck)
                {
                    if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.5f)
                    {
                        changeTo(MachineState::Stuck);
                    }
                    else
                    {
                        m_layEggBehavior->m_importanceLevel = 0.0f;
                    }
                }
            }
            break;
        case MachineState::Lay:
            MACHINE_DELEGATE()
            {
                if (m_layEggBehavior->eggType != nullptr)
                {
                    m_layEggBehavior->layTime += dt;
                    ComponentCreature *creature = m_layEggBehavior->componentCreature;
                    if (creature->componentBody->standingOnValue != 0)
                    {
                        SubsystemTimeOfDay *timeOfDay = GameSingleton::singletonPtr->getSingleton<SubsystemTimeOfDay>();
                        creature->componentLocomotion->setLookOrder(
                            Vector2(0.0f, 0.25f * MathUtils::Sin<float>(20.0f * timeOfDay->getGameTime()) + m_layEggBehavior->layTime / 3.0f) -
                            creature->componentLocomotion->lookAngles
                        );
                        if (m_layEggBehavior->layTime >= 3.0f)
                        {
                            m_layEggBehavior->m_importanceLevel = 0.0f;
                            int32_t value = Terrain::MakeBlockValue(EggBlock::Index(), 0, EggBlock::SetIsLaid(EggBlock::SetEggType(0, m_layEggBehavior->eggType->eggTypeIndex), true));
                            Matrix matrix = creature->componentBody->getMatrix();

                            BoundingBox boundingBox = creature->componentBody->getBoundingBox();
                            Vector3 position = 0.5f * (boundingBox.Min + boundingBox.Max);
                            Vector3 value2 = 3.0f * Vector3::Normalize(-matrix.getForward() + 
                                0.1f * matrix.getUp() +
                                0.2f * GameSingleton::gameRandom->getFloat(-1.0f, 1.0f) * matrix.getRight());
                            
                            SubsystemPickables *subsystemPickables = GameSingleton::singletonPtr->getSingleton<SubsystemPickables>();
                            subsystemPickables->addPickable(value, 1, position, std::make_shared<Vector3>(value2), nullptr);
                        }
                    }
                    else if (m_layEggBehavior->layTime >= 3.0f)
                    {
                        m_layEggBehavior->m_importanceLevel = 0.0f;
                    }
                }
                else
                {
                    m_layEggBehavior->m_importanceLevel = 0.0f;
                }
            }
            break;
        }
    }

    void ComponentLayEggBehavior::StateMachine::leave() {}

    // **************************************



    ComponentLayEggBehavior::~ComponentLayEggBehavior()
    {
        delete m_stateMachine;
    }

    float ComponentLayEggBehavior::getImportanceLevel()
    {
        return m_importanceLevel;
    }

    void ComponentLayEggBehavior::update(float dt)
    {
        if (eggType != nullptr && GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < layFrequency * dt)
        {
            m_importanceLevel = GameSingleton::gameRandom->getFloat(1.0f, 2.0f);
        }
        if (isActive())
        {
            m_stateMachine->update(dt);
        }
        else
        {
            m_stateMachine->changeTo(MachineState::Inactive);
        }
    }
    
    static const std::string componentName = "LayEggBehavior";
    const std::string &ComponentLayEggBehavior::getName() const
    {
        return componentName;
    }
    const std::string &ComponentLayEggBehavior::GetName()
    {
        return componentName;
    }
    void ComponentLayEggBehavior::load(const nlohmann::json &jsonData)
    {
        eggType = nullptr;
        componentCreature = GameSingleton::gameRegistry->get<ComponentCreature *>(entity);
        componentPathfinding = GameSingleton::gameRegistry->get<ComponentPathfinding *>(entity);

        // 查找蛋的信息
        EntityData* entityData = GameSingleton::gameRegistry->get<EntityData *>(entity);
        auto &eggTypeVec = GameSingleton::blocksManager->blocks[EggBlock::Index()]->asBlock<EggBlock*>()->eggTypes;
        for (EggType &findEggType : eggTypeVec)
        {
            if (findEggType.entityName == entityData->ObjectName)
            {
                eggType = &findEggType;
                // Log::Info(fmt::format("查到到蛋数据,id: {},名称:{}", eggType->eggTypeIndex, eggType->entityName));
                break;
            }
        }

        layFrequency = jsonData["LayFrequency"].get<float>();

        m_stateMachine = new StateMachine(this);
    }

}
